﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JsonToSql
{
    /// <summary>
    /// Condition format in json
    /// </summary>
    public class JsonCondition
    {
        private string key;
        /// <summary>
        /// Field name in condition
        /// </summary>
        public string Key
        {
            get
            {
                return key;
            }
        }
        private string value;
        /// <summary>
        /// Value used in condition
        /// </summary>
        public string Value
        {
            get
            {
                return value;
            }
        }
        /// <summary>
        /// Operator for condition
        /// </summary>
        public string ConditionOperator
        {
            get
            {
                return this.token["ConditionOperator"].ToString();
            }
        }
        /// <summary>
        /// Operator which join previous condition
        /// </summary>
        public string Operator
        {
            get
            {
                return this.token["Operator"].ToString();
            }
        }
        private JToken token;
        private JsonTableCondition parent;
        /// <summary>
        /// Parent table
        /// </summary>
        public JsonTableCondition Parent
        {
            get
            {
                return parent;
            }
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="token">Token text format of condition</param>
        /// <param name="parent">Parent table</param>
        public JsonCondition(JToken token, JsonTableCondition parent)
        {
            this.token = token;
            this.parent = parent;
            if (token != null)
            {
                JObject obj = token.ToObject<JObject>();

                foreach (JProperty prop in obj.Properties())
                {
                    if (prop.Name != "NextOperator" && prop.Name != "ConditionOperator")
                    {
                        key = prop.Name;
                        value = prop.Value.ToString();
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// Add next condition to result
        /// </summary>
        /// <param name="cmd">cmd command</param>
        /// <param name="index">order of condition</param>
        /// <returns>result condition</returns>
        public void AddCondition(SqlCommand cmd, int index)
        {
            if(cmd==null)
            {
                return;
            }
            if(!isValidConditionOperator(ConditionOperator))
            {
                throw new FormatException("Wrong condition operator");
            }
            if (!isValidOperator(Operator))
            {
                throw new FormatException("Wrong operator");
            }
            

            string prepCondition = string.Format(CultureInfo.InvariantCulture, " {0} t.[{1}]{2}@PC{3} ", index>0 ? this.Operator : "",
                this.Key, this.ConditionOperator, index);
            cmd.CommandText += prepCondition;
            
            cmd.Parameters.AddWithValue(string.Format(CultureInfo.InvariantCulture,"PC{0}", index),
               this.Value );
        }
        private static bool isValidConditionOperator(string conditionOperator)
        {
            if (conditionOperator == null)
                return false;
            switch (conditionOperator)
            {
                case "=": return true;
                case "<": return true;
                case ">": return true;
                case "<>": return true;
                case ">=": return true;
                case "<=": return true;
                default: return false;
            }
        }
        private static bool isValidOperator(string op)
        {
            if (op == null)
                return false;
            switch (op.ToUpperInvariant())
            {
                case "AND": return true;
                case "OR": return true;
                default: return false;
              
            }
        }
    }
}
